package com.tang.model.state.examination;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author tangyuan2meicloud.com
 * @DATE 2021/9/5 17:21
 * @Desc
 * @Remarks
 */
@Component("examineStateListener")
public class ExamineServiceImpl implements IExamineService {

    @Autowired
    private StateMachine<ExamineStatusEnum, ExamineStatusActionEnum> stateMachine;

    @Autowired
    private StateMachinePersister<ExamineStatusEnum, ExamineStatusActionEnum, ExamineOrder> stateMachinePersister;

    //订单ID的number开始值
    private int idStartForNumber = 1;
    private Map<Integer, ExamineOrder> orders = new ConcurrentHashMap<>();

    @Override
    public ExamineOrder reserve() {
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 尝试预约");
        ExamineOrder examineOrder = createExamineOrder();
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 尝试成功,预约号码：" + examineOrder.getId());
//       创建消息体
        Message message = MessageBuilder.withPayload(ExamineStatusActionEnum.RESERVE).
                setHeader("examineOrder", examineOrder).build();
        if (!sendEvent(message, examineOrder)) {
            System.out.println("线程名称：" + Thread.currentThread().getName() + " 预约失败, 状态异常，订单号：" + examineOrder.getId());
        }
        return examineOrder;
    }

    public synchronized ExamineOrder createExamineOrder() {
        ExamineOrder examineOrder = new ExamineOrder();
        examineOrder.setId(idStartForNumber++);
        examineOrder.setStatus(ExamineStatusEnum.NO_APPOINTMENT);
        orders.put(examineOrder.getId(), examineOrder);
        return examineOrder;
    }

    @Override
    public ExamineOrder takeNumber(Integer id) {
        if (!orders.containsKey(id)) {
            throw new RuntimeException("单号不存在");
        }
        ExamineOrder examineOrder = orders.get(id);
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 线下取号操作");
        //       创建消息体
        Message message = MessageBuilder.withPayload(ExamineStatusActionEnum.TAKE_NUMBER).
                setHeader("examineOrder", examineOrder).build();
        if (!sendEvent(message, examineOrder)) {
            System.out.println("线程名称：" + Thread.currentThread().getName() + " 线下取号失败, 状态异常，订单号：" + examineOrder.getId());
        }
        return examineOrder;
    }

    @Override
    public ExamineOrder entryInformation(Integer id) {
        if (!orders.containsKey(id)) {
            throw new RuntimeException("单号不存在");
        }
        ExamineOrder examineOrder = orders.get(id);
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 填报操作");
        //       创建消息体
        Message message = MessageBuilder.withPayload(ExamineStatusActionEnum.ENTRY_INFORMATION).
                setHeader("examineOrder", examineOrder).build();
        if (!sendEvent(message, examineOrder)) {
            System.out.println("线程名称：" + Thread.currentThread().getName() + " 填报失败, 状态异常，订单号：" + examineOrder.getId());
        }
        return examineOrder;
    }

    @Override
    public ExamineOrder payment(Integer id) {
        if (!orders.containsKey(id)) {
            throw new RuntimeException("单号不存在");
        }
        ExamineOrder examineOrder = orders.get(id);
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 支付操作");
        //       创建消息体
        Message message = MessageBuilder.withPayload(ExamineStatusActionEnum.PAYMENT).
                setHeader("examineOrder", examineOrder).build();
        if (!sendEvent(message, examineOrder)) {
            System.out.println("线程名称：" + Thread.currentThread().getName() + " 支付失败, 状态异常，订单号：" + examineOrder.getId());
        }
        return examineOrder;
    }

    @Override
    public ExamineOrder examine(Integer id) {
        if (!orders.containsKey(id)) {
            throw new RuntimeException("单号不存在");
        }
        ExamineOrder examineOrder = orders.get(id);
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 检查操作");
        //       创建消息体
        Message message = MessageBuilder.withPayload(ExamineStatusActionEnum.EXAMINE).
                setHeader("examineOrder", examineOrder).build();
        if (!sendEvent(message, examineOrder)) {
            System.out.println("线程名称：" + Thread.currentThread().getName() + " 检查失败, 状态异常，订单号：" + examineOrder.getId());
        }
        return examineOrder;
    }

    @Override
    public ExamineOrder published(Integer id) {
        if (!orders.containsKey(id)) {
            throw new RuntimeException("单号不存在");
        }
        ExamineOrder examineOrder = orders.get(id);
        System.out.println("线程名称：" + Thread.currentThread().getName() + " 发布结果");
        //       创建消息体
        Message message = MessageBuilder.withPayload(ExamineStatusActionEnum.PUBLISHED).
                setHeader("examineOrder", examineOrder).build();
        if (!sendEvent(message, examineOrder)) {
            System.out.println("线程名称：" + Thread.currentThread().getName() + " 发布结果失败, 状态异常，订单号：" + examineOrder.getId());
        }
        return examineOrder;
    }

    //    发布消息
    private synchronized boolean sendEvent(Message<ExamineStatusActionEnum> message, ExamineOrder order) {
        boolean result = false;
        try {
            stateMachine.start();
            //尝试恢复状态机状态
            stateMachinePersister.restore(stateMachine, order);
            //添加延迟用于线程安全测试
            Thread.sleep(1000);
            result = stateMachine.sendEvent(message);
            //持久化状态机状态
            stateMachinePersister.persist(stateMachine, order);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            stateMachine.stop();
        }
        return result;
    }

}
